module Basic =
struct
  type ('input, 'store) basic_elt = 
      <
      name: string;
      activate: 'input -> unit;
(*      store: 'store;*)
  (*    map: ('store -> 'a) -> ('input, 'a) basic;*)
      to_directory: 'store Directory.directory;
      >
  ;;
  
  class ['input, 'store, 'content] file ~name ~(content: 'content) 
        ~(f: 'input -> 'content -> unit) 
        ~(of_content: string -> 'content -> 'store) =
  object(self)
      method included = (self :> ('input, 'store) basic_elt)
      method name = name
(*      method store = store*)
      method content = content
      method activate input = f input content
  (*    method map f act = new  file ~store:(f store) ~f:act*)
      method to_directory: 'store Directory.directory = 
              Directory.File (of_content name content)
  end
  
  class ['input, 'store, 'output] dir
          ~(name: string)
          ~(transform: 'input -> 'output)
          (contents: ('output, 'store) basic_elt list)  = 
  object(self)
      method included = (self :> ('input, 'store) basic_elt)
      method name = name
(*      method store = store*)
      method activate input =
          let output = transform input in
          List.iter (fun obj -> obj#activate output) contents
  (*    method map f transform = new dir *)
      method to_directory = Directory.make name 
          (List.map (fun obj -> obj#to_directory) contents)
  end
  ;;

  class ['input, 'store, 'content, 'output] dir_default 
          ~(name: string)
          ~(transform: 'input -> 'content -> 'output)
          ~(default:  ('input, 'store, 'content) file)
          (contents: ('output, 'store) basic_elt list)  = 
  object(self)
      method included = (self :> ('input, 'store) basic_elt)
      method name = name
(*      method store = store*)
      method activate input =
          let output = transform input default#content in
          default#activate output;
          List.iter (fun obj -> obj#activate output) contents
  (*    method map f transform = new dir *)
      method to_directory = Directory.make name (default#to_directory ::
          (List.map (fun obj -> obj#to_directory) contents))
  end
  ;;
  
  let file ~name ~content ~f ~of_content = 
          (new file ~name ~content ~f ~of_content)#included
  let dir ~name ~transform contents = 
          (new dir ~name ~transform contents)#included
  let dir_default ~name ~transform ~default contents =
          (new dir_default ~name ~transform ~default contents)#included

end

module Make_store(Store: sig type t end) =
struct
  class ['input, 'content] file ~name ~content ~f ~of_content = 
          ['input, Store.t, 'content] Basic.file ~name ~content ~f ~of_content
  class ['input, 'output] dir ~name ~transform contents =
      ['input, Store.t, 'output] Basic.dir 
           ~name ~transform contents
  class ['input, 'content, 'output] dir_default 
        ~name ~transform ~default contents =
      ['input, Store.t, 'content, 'output] Basic.dir_default 
           ~name ~transform ~default contents
           
  let file ~name ~content ~f ~of_content = 
          (new file ~name ~content ~f ~of_content)#included
  let dir ~name ~transform contents = 
          (new dir ~name ~transform contents)#included
  let dir_default ~name ~transform ~default contents =
          (new dir_default ~name ~transform ~default contents)#included

end
